#pragma once

#include <memory_allocator.h>
#include <ftp_file.h>
#include <user_manager.h>
#include <TcpConnection.h>
#include <Accepter.h>
#include <InetAddress.h>
#include <algorithm>
#include <deque>
#include <map>

// 每个用户最大数据连接数
constexpr int MAX_DATA_CONNECTION_NUM_PER_USER = 3;

// 读写速度限制
constexpr int TOKEN_BUCKET_TICKET_LEN = 100; // 1000ms
constexpr int TOKEN_BUCKET_READ_RATE = 1024 * 1024 * 10; // 100m/s
constexpr int TOKEN_BUCKET_READ_BURST = 10 * 1024 * 1024;
constexpr int TOKEN_BUCKET_WRITE_RATE = 1024 * 1024 * 10; // 100m/s
constexpr int TOKEN_BUCKET_WRITE_BURST = 10 * 1024 * 1024;

struct Command {
	std::string command_;
	std::string param_;
};

struct FileTask{
	FileTask() = default;
	FileTask(const std::shared_ptr<void>& ptr, const std::string& filename) :
		pSession_(ptr),
		filename_(filename)
	{
	}
	
	std::shared_ptr<void> pSession_;
	std::string filename_;
};

class FTPSession : public std::enable_shared_from_this<FTPSession> {
	enum class State
	{
		UNLOGIN = 0, 
		LOGINING,
		LOGINED, 
	};
public:
	FTPSession(const std::shared_ptr<TcpConnection>& conn);

	std::string name() { return name_; }

	bool parseCmd(const std::string& cmdline);

	bool handleCmd(std::string cmd, const std::string& param);

	~FTPSession();
private:
	void sendFtpMsg(int code, const std::string& msg);

	bool checkLoginState() const;

	/// <summary>
	/// 检测是否在用户的根目录下
	/// </summary>
	/// <param name="filename"></param>
	/// <returns></returns>
	bool checkFilePermission(const std::string& filename);

	bool checkCmdPermission( const std::string& cmd);

	void handleDataConnTask(const std::function<void()>& task);

	bool handleAUTH(const std::string& param);

	bool handleUSER(const std::string& param);
	
	bool handlePASS(const std::string& param);

	bool handleQUIT(const std::string& param);
	
	bool handlePROT(const std::string& param);
	
	bool handlePBSZ(const std::string& param);

	bool handlePASV(const std::string& param);

	bool handleSYST(const std::string& param);

	bool handleFEAT(const std::string& param);

	bool handleOPTS(const std::string& param);

	bool handleTYPE(const std::string& param);

	bool handleSTRU(const std::string& param);

	bool handleMODE(const std::string& param);
	
	bool handleLIST(const std::string& param);

	bool handleSTOR(const std::string& param);
	
	bool handleRETR(const std::string& param);

	bool handleSIZE(const std::string& param);

	bool handleREST(const std::string& param);

	bool handlePWD(const std::string& param);

	bool handleMKD(const std::string& param);

	bool handleRMD(const std::string& param);

	bool handleCWD(const std::string& param);

	bool handleCDUP(const std::string& param);

	bool handleNOOP(const std::string& param);

	bool handleRNFR(const std::string& param);

	bool handleRNTO(const std::string& param);

	bool handleDELE(const std::string& param);

	bool handleHELP(const std::string& param);

	void readFileCallback(std::shared_ptr<FTPFile> file, const std::shared_ptr<TcpConnection>& conn, Buffer& inBuffer);

	void startSendFile(std::shared_ptr<FTPFile> file);

	void sendFtpFile(const std::shared_ptr<FTPFile>& file);
	
	void startRecvFile(const std::shared_ptr<FTPFile>& file, Buffer& inBuffer);

	/// <summary>
	/// 将用户请求的访问路径param拼接成当前用户的绝对路径
	/// </summary>
	/// <param name="param">用户请求路径</param>
	/// <returns>用户文件的绝对路径</returns>
	std::string toLocalPath(const std::string& param);

private:
	bool isSSL_;
	//std::unordered_map<std::string, int> fileStateMap_; // 文件权限处理部分交给系统
	bool isTransferring_; // 正在传输数据
	std::string name_;	// 会话名称
	std::unique_ptr<FTPUser> user_;
	std::size_t offset_; // 文件偏移量，为rest指令准备
	Command lastCommand_; // 上一条指令
	Command currCommand_; // 当前指令
	std::deque<std::function<void()>> taskList_; // 任务队列，stor存入前面，retr存入后面。取出任务时优先取出前面
	char* buffer_{ new char[BLOCK_SIZE] };
	State loginState_;
	std::shared_ptr<TcpConnection> cmdConn_; // 控制连接，listenCallback后由TcpServer设置
	std::unique_ptr<Accepter> dataAccepter_; // 数据连接监听器
	std::shared_ptr<TcpConnection> dataConn_; // 仅保留最近一次数据连接
};